package com.lancoo.ccas53.arrangecourse.coursescheduling.campusscheduling;

import cn.hutool.core.util.StrUtil;
import com.lancoo.ccas53.arrangecourse.coursescheduling.allocatetimeslotroom.AllocateNoClashTimeslotRoom;
import com.lancoo.ccas53.arrangecourse.coursescheduling.allocatetimeslotroom.AllocateTimeslotRoom;
import com.lancoo.ccas53.arrangecourse.coursescheduling.assignlist.NoClashAssign;
import com.lancoo.ccas53.arrangecourse.coursescheduling.assignlist.NormalAssign;
import com.lancoo.ccas53.arrangecourse.dataprocess.GenerateSchedulingData;
import com.lancoo.ccas53.arrangecourse.entities.ClassHour;
import com.lancoo.ccas53.arrangecourse.entities.TeachingClassUnit;
import com.lancoo.ccas53.arrangecourse.entities.TimeslotRoom;
import com.lancoo.ccas53.arrangecourse.rulecheck.RuleInit;
import com.lancoo.ccas53.pojo.dto.ArrangeCourseRuleDto;
import com.lancoo.ccas53.pojo.dto.ArrangeTeacherRuleDto;
import com.lancoo.ccas53.pojo.dto.ArrangeTeachingClassDto;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * @Author: liufeng
 * @CreateTime: 2024-09-11  17:05
 * @Description:
 */
@Slf4j
public class MergeTeachingClassScheduling extends GenerateSchedulingData {
    //声明排课的对象
    protected NormalAssign normalAssign;


    /**
     * 构造函数，尽量排规则处理类，同时传递跨校区排课标识
     * @param ruleInit 排课规则初始化对象
     * @param withRule
     */
    public MergeTeachingClassScheduling(RuleInit ruleInit, boolean withRule) {
        //初始化排课的对象
        if (normalAssign == null) {
            //初始化排课使用的教室课时分配的类，分配无冲突的教室课时分组信息；
            AllocateTimeslotRoom allocateTimeslotRoom = new AllocateNoClashTimeslotRoom();
            //初始化拆班排课，需要满足的规则
            normalAssign = new NoClashAssign(withRule ?
                    ruleInit.getFixCourseRule() : ruleInit.getNoClashBaseRule(), allocateTimeslotRoom);
        }
    }

    public LinkedList<TeachingClassUnit> start(Integer taskId,
                                               List<ArrangeTeachingClassDto> teachingClassList,
                                               LinkedList<TimeslotRoom> timeslotRoomList,
                                               ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                                               List<ArrangeTeacherRuleDto> teacherRuleList,
                                               List<ArrangeCourseRuleDto> courseRuleList,
                                               LinkedList<TeachingClassUnit> leaveList,
                                               boolean withRule) {
        if ((teachingClassList != null && !teachingClassList.isEmpty())
            || (leaveList != null && !leaveList.isEmpty()) ) {
            if (timeslotRoomList == null || timeslotRoomList.isEmpty()) {
                log.error("SplitTeachingClassScheduling--start:没有用于排课的教室课时分组信息~！！");
                return null;
            }
            List<ArrangeTeachingClassDto> mergeTeachingClassList = new ArrayList<>();
            if (withRule){
                //将尽量排的教学班，做好标记, 并从教学班列表中，筛选出尽量排的教学班
                mergeTeachingClassList = findMergeTeachingClass(teachingClassList,teacherRuleList, courseRuleList);
            }
            //开始合班排课
            return startMergeTeachingClass(taskId, mergeTeachingClassList, timeslotRoomList, classHourMap, leaveList);
        }

        log.info("FixScheduling--start:未设置合班，无需合班排排课~！");
        return null;
    }

    private LinkedList<TeachingClassUnit> startMergeTeachingClass(Integer taskId,
                                                                  List<ArrangeTeachingClassDto> teachingClassList,
                                                                  LinkedList<TimeslotRoom> timeslotRoomList,
                                                                  ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                                                                  LinkedList<TeachingClassUnit> leaveList) {
        if (teachingClassList != null && !teachingClassList.isEmpty()
                || (leaveList != null && !leaveList.isEmpty()) ) {
            log.info("FixScheduling--start:开始进行合班排排课，需要进行合班排的教学班数量为："+teachingClassList.size());
            //进行优先排排课
            LinkedList<TeachingClassUnit> teachingClassUnitList = normalAssign.start(taskId,
                    teachingClassList, leaveList, timeslotRoomList, classHourMap);

            log.info("#FixScheduling.start#--合班排排课完毕，剩余未分配教学班排课单元数量"+
                    (teachingClassUnitList!=null?teachingClassUnitList.size():0));

            return teachingClassUnitList;

        }

        return null;
    }

    private List<ArrangeTeachingClassDto> findMergeTeachingClass(
                                            List<ArrangeTeachingClassDto> teachingClassList,
                                            List<ArrangeTeacherRuleDto> teacherRuleList,
                                            List<ArrangeCourseRuleDto> courseRuleList) {
        List<ArrangeTeachingClassDto> mergeTeachingClassList = null;
        if (teachingClassList != null && !teachingClassList.isEmpty()) {
            //筛选出合班的教学班
            mergeTeachingClassList = teachingClassList.stream()
                    .filter(teachingClass -> StrUtil.isNotEmpty(teachingClass.getToClass())
                                && teachingClass.getToClass().contains(",")
//                                && teachingClass.getToClass().split(",").length > 1
                    )
                    .collect(Collectors.toList());
        }

        if (mergeTeachingClassList == null
                || mergeTeachingClassList.isEmpty()) {
            log.info("FixScheduling--markFixTimeslot:设置了优先排规则，但是当前排课的教学班中，不包括当前教师或课程信息");
        } else {
            //将优先排的教学班，从总的教学班中排除掉
            teachingClassList.removeAll(mergeTeachingClassList);

            if(teacherRuleList != null && !teacherRuleList.isEmpty()) {
                log.info("FixScheduling--markFixTimeslot:获取教师优先排规则{}条", teacherRuleList.size());
                //将教师优先排设置的课时信息，添加到教学班列表
                mergeTeachingClassList = markTeacherFixTimeslot(mergeTeachingClassList, teacherRuleList);
            }

            if (courseRuleList != null && !courseRuleList.isEmpty()) {
                log.info("FixScheduling--markFixTimeslot:获取课程优先排规则{}条", courseRuleList.size());
                //将课程优先排设置的课时信息，添加到教学班列表
                mergeTeachingClassList = markCourseFixTimeslot(mergeTeachingClassList, courseRuleList);
            }
        }

        return mergeTeachingClassList;
    }

    /**
     * 将教师优先排设置的课时信息，添加到教学班列表
     * @param teachingClassList 教学班列表
     * @param teacherRuleList 教师设置的优先排列表
     * @return
     */
    private List<ArrangeTeachingClassDto> markTeacherFixTimeslot(List<ArrangeTeachingClassDto> teachingClassList,
                                                                 List<ArrangeTeacherRuleDto> teacherRuleList) {
        if (teachingClassList != null && !teachingClassList.isEmpty()
                && teacherRuleList != null && !teacherRuleList.isEmpty()) {
            //筛选出教师尽量排的规则
            List<ArrangeTeacherRuleDto> teacherFixRuleList = teacherRuleList.stream()
                    .filter(rule -> rule.getFlag().equals(2))
                    .collect(Collectors.toList());

            log.info("FixScheduling--markTeacherFixTimeslot:获取教师优先排规则{}条", teacherFixRuleList.size());
            if (teacherFixRuleList != null && !teacherFixRuleList.isEmpty()) {
                for (ArrangeTeacherRuleDto teacherRule : teacherFixRuleList) {
                    //定义列表遍历的迭代器
                    Iterator iterator = teachingClassList.iterator();
                    while (iterator.hasNext()) {
                        ArrangeTeachingClassDto teachingClass = (ArrangeTeachingClassDto) iterator.next();
                        //判断教学班教师中，是否包含该教师的固定排信息
                        if (isTeacherIdExist(teachingClass.getTeacherIds(), teacherRule.getTeacherId() + "")) {

                            //获取课时编码，0102
                            String timeslotCode = teacherRule.getTimeCode();
                            //更新教学班信息中的，尽量排字符串属列表性
                            teachingClass.setFixTimeslotCodes(updateFixTimeslotCodes(teachingClass.getFixTimeslotCodes(),
                                    timeslotCode));
                        }
                    }
                }
            } else {
                log.info("FixScheduling--markTeacherFixTimeslot:没有需要标记的教师尽量排规则");
            }
        }

        return teachingClassList;
    }

    /**
     * 将课程优先排设置的课时信息，标记到教学班列表
     * @param teachingClassList 教学班列表
     * @param courseRuleList 课程优先排规则列表
     * @return
     */
    private List<ArrangeTeachingClassDto> markCourseFixTimeslot(List<ArrangeTeachingClassDto> teachingClassList,
                                                                List<ArrangeCourseRuleDto> courseRuleList) {
        //将课程优先排的课时，标记到教学班
        if (teachingClassList != null && !teachingClassList.isEmpty()
                && courseRuleList != null && !courseRuleList.isEmpty()) {

            //筛选出课程尽量排的规则
            List<ArrangeCourseRuleDto> courseFixList = courseRuleList.stream()
                    .filter(rule -> rule.getFlag().equals(2))
                    .collect(Collectors.toList());
            log.info("FixScheduling--markCourseFixTimeslot:获取课程优先排规则{}条", courseFixList.size());

            if (courseFixList != null && !courseFixList.isEmpty()) {
                //定义遍历课程优先排列表
                for (ArrangeCourseRuleDto courseRule : courseRuleList) {
                    for (ArrangeTeachingClassDto teachingClass : teachingClassList) {
                        //通过教学班id，进行匹配
                        if (courseRule.getTeachingClassId().equals(teachingClass.getTeachingClassId())
                                && Objects.equals(courseRule.getHourType(), teachingClass.getHourType())) {
                            //将数据添加到优先排的教学班列表
                            //获取课时编码，0102
                            String timeslotCode = courseRule.getTimeCode();
                            //更新教学班信息中的，尽量排字符串属列表性
                            teachingClass.setFixTimeslotCodes(updateFixTimeslotCodes(teachingClass.getFixTimeslotCodes(),
                                    timeslotCode));
                        }
                    }
                }
            } else {
                log.info("FixScheduling--markCourseFixTimeslot:没有需要标记的课程尽量排规则");
            }
        }
        return teachingClassList;
    }

    /**
     * 更新教师尽量排规则列表信息
     * @param fixTimeslotCodes 原来的教师尽量排规则列表
     * @param timeslotCode 添加到优先排规则的课时编码信息
     * @return
     */
    private List<String> updateFixTimeslotCodes(List<String> fixTimeslotCodes,
                                                String timeslotCode) {

        if (fixTimeslotCodes == null) {
            //创建列表
            fixTimeslotCodes = new ArrayList<>();
        }
        //如果不存在重复的，则将其加入列表
        if (!fixTimeslotCodes.contains(timeslotCode)) {
            //将这条规则加入列表
            fixTimeslotCodes.add(timeslotCode);
        }

        return fixTimeslotCodes;
    }

}
